package cn.matezk.lianlian.controller;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.crypto.digest.DigestUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import cn.matezk.lianlian.service.IDeviceService;
import cn.matezk.lianlian.service.IEventService;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;

@RestController
@RequestMapping("tencent")
@Slf4j
public class TencentController {
    @Autowired
    private IEventService eventService;
    @Autowired
    private IDeviceService deviceService;
    @Value("${tencent.token}")
    private String token;

    @GetMapping(value = {"", "event", "property", "state", "ota", "propertyForward"})
    public String callback(HttpServletRequest request) throws WxErrorException {
        String nonce = request.getHeader("Nonce");
        String timestamp = request.getHeader("Timestamp");
        String signature = request.getHeader("Signature");
        boolean allow = pushAuth(token, nonce, timestamp, signature);
        return allow ? request.getHeader("Echostr") : "";
    }

    @PostMapping("propertyForward")
    public void propertyForward(@RequestBody JSONObject property) throws InterruptedException {
        String productId = property.getStr("productid");
        String deviceName = property.getStr("devicename");
        if (!property.containsKey("payload"))   return;
        JSONObject payload = property.getJSONObject("payload");
        if (!payload.containsKey("params"))    return;
        JSONObject params = payload.getJSONObject("params");
        String deviceId = productId.concat("/").concat(deviceName);
        deviceService.propertyForward(deviceId, property.getDate("timemills"), params);
    }

    @PostMapping("property")
    public void property(@RequestBody JSONObject property) throws InterruptedException {
        String productId = property.getStr("productid");
        String deviceName = property.getStr("devicename");
        if (!property.containsKey("payload"))   return;
        JSONObject payload = property.getJSONObject("payload");
        if (!payload.containsKey("params"))    return;
        JSONObject params = payload.getJSONObject("params");
        String deviceId = productId.concat("/").concat(deviceName);
        deviceService.property(deviceId, property.getDate("timemills"), params);
    }

    @PostMapping("event")
    public void event(@RequestBody JSONObject event) throws WxErrorException {
        log.info(event.toStringPretty());
        String productId = event.getStr("productid");
        String deviceName = event.getStr("devicename");
        JSONObject payload = event.getJSONObject("payload");
        if (payload.containsKey("events")) {
            JSONArray events = payload.getJSONArray("events");
            List<JSONObject> tEvents = JSONUtil.toList(events, JSONObject.class);
            for (JSONObject ev : tEvents) {
                try {
                    eventService.handle(productId, deviceName, ev.getStr("eventId"), ev.getStr("type"), event.getDate("timemills"), ev.getJSONObject("params"));
                } catch (Exception e) {
                    log.error(e.getMessage());
                }
            }
        } else {
            try {
                eventService.handle(productId, deviceName, payload.getStr("eventId"), payload.getStr("type"), event.getDate("timemills"), payload.getJSONObject("params"));
            } catch (Exception e) {
                log.error(e.getMessage());
            }
        }
    }

    @PostMapping("state")
    public void state(@RequestBody JSONObject object) {
        String deviceId = object.getStr("productid").concat("/").concat(object.getStr("devicename"));
        String state = object.getJSONObject("payload").getStr("event");
        Date eventTime = object.getDate("timemills");
        deviceService.stateChanged(deviceId, state, eventTime);
    }

    @PostMapping("ota")
    public void ota(@RequestBody JSONObject report) {
        JSONObject payload = report.getJSONObject("payload");
        if (ObjectUtil.isNull(payload)) return;
        if (ObjectUtil.notEqual("report_version", payload.getStr("type")))  return;
        if (!payload.containsKey("report")) return;
        String productId = report.getStr("productid");
        String deviceName = report.getStr("devicename");
        String version = payload.getJSONObject("report").getStr("version");
        deviceService.versionReport(String.format("%s/%s", productId, deviceName), version);
    }

    private boolean pushAuth(String token, String nonce, String timestamp, String signature) {
        List<String> fields = new ArrayList<>();
        fields.add(token);
        fields.add(nonce);
        fields.add(timestamp);
        Collections.sort(fields);
        String sign = DigestUtil.sha1Hex(String.join("", fields));
        return sign.equals(signature);
    }
}
